/*
 * @Author: xiehangyun 
 * @Date: 2025-02-21 17:15:24 
 * @Last Modified by: xiehangyun
 * @Last Modified time: 2025-02-22 14:53:10
 */

import { EventDispatcher } from "three";

interface BoundingBox {
  x: number;
  y: number;
  width: number;
  height: number;
}

type Direction = 'horizontal' | 'vertical';
type EdgeCheckFn = (value: number) => boolean;

class GraffitiEditor extends EventDispatcher {
  constructor() {
    super();
  }

  init(lowerCanvas: HTMLCanvasElement, upperCanvas: HTMLCanvasElement) {
    this.lowerCanvas = lowerCanvas;
    this.upperCanvas = upperCanvas;
    this.lowerCanvasCtx = this.lowerCanvas.getContext('2d')!;
    this.upperCanvasCtx = this.upperCanvas.getContext('2d')!;
    this.buildEvent();
    //重置绘制区域
    this.drawArea = {
      x: 1024,
      y: 1024,
      width: 0,
      height: 0,
    };

  }

  // 用于显示绘制的涂鸦
  lowerCanvas!: HTMLCanvasElement;
  lowerCanvasCtx!: CanvasRenderingContext2D;

  //用于显示画笔的canvas
  upperCanvas!: HTMLCanvasElement;
  upperCanvasCtx!: CanvasRenderingContext2D;

  // 开始绑定事件
  buildEvent() {
    this.upperCanvas.addEventListener('mousedown', (e) => {
      this.draw = true;
      this.lastX = e.offsetX;
      this.lastY = e.offsetY;
      this.drawBrush(e);
      document.addEventListener('mouseup', () => {
        this.draw = false;
      });
    });

    this.upperCanvas.addEventListener('mousemove', (e) => {
      this.drawBrush(e);
    });
    //鼠标离开画布时清空画布
    this.upperCanvas.addEventListener('mouseleave', () => {
      this.upperCanvasCtx.clearRect(0, 0, this.upperCanvas.width, this.upperCanvas.height);
    });
  }

  // 使用 upperCanvasCtx 绘制圆形
  drawBrush(e: MouseEvent) {

    //在upperCanvasCtx上绘制画笔的当前的位置 粗细 颜色 如果是橡皮擦 则是空心的黑色圆形
    this.upperCanvasCtx.clearRect(0, 0, this.upperCanvas.width, this.upperCanvas.height);

    if (this.brushType === 'eraser') {
      this.upperCanvasCtx.beginPath();
      this.upperCanvasCtx.arc(e.offsetX, e.offsetY, Math.max(this.brushSize, 6) / 2, 0, Math.PI * 2);
      this.upperCanvasCtx.strokeStyle = '#000000';
      this.upperCanvasCtx.lineWidth = 2;
      this.upperCanvasCtx.stroke();
    } else {
      this.upperCanvasCtx.beginPath();
      this.upperCanvasCtx.strokeStyle = this.brushColor;
      this.upperCanvasCtx.lineWidth = this.brushSize;
      this.upperCanvasCtx.arc(e.offsetX, e.offsetY, Math.max(this.brushSize, 6) / 2, 0, Math.PI * 2);
      this.upperCanvasCtx.fillStyle = this.brushColor;
      this.upperCanvasCtx.fill();
    }

    if (!this.draw) return;

    // 擦除一个圆形的范围
    if (this.brushType === 'eraser') {
      this.lowerCanvasCtx.beginPath();
      this.lowerCanvasCtx.lineWidth = this.brushSize;
      this.lowerCanvasCtx.lineCap = 'round'; // 圆形线帽
      this.lowerCanvasCtx.strokeStyle = "#ffffff";
      this.lowerCanvasCtx.globalCompositeOperation = 'destination-out';
      this.lowerCanvasCtx.moveTo(this.lastX, this.lastY);
      this.lowerCanvasCtx.lineTo(e.offsetX, e.offsetY);
      this.lowerCanvasCtx.stroke();
    } else {
      this.lowerCanvasCtx.beginPath();
      this.lowerCanvasCtx.globalCompositeOperation = "source-over";
      this.lowerCanvasCtx.lineWidth = this.brushSize;
      this.lowerCanvasCtx.lineCap = 'round'; // 圆形线帽
      this.lowerCanvasCtx.strokeStyle = this.brushColor;
      this.lowerCanvasCtx.moveTo(this.lastX, this.lastY);
      this.lowerCanvasCtx.lineTo(e.offsetX, e.offsetY);
      this.lowerCanvasCtx.stroke();
    }
    [this.lastX, this.lastY] = [e.offsetX, e.offsetY];

    //记录绘制区域
    this.drawArea.x = Math.min(this.drawArea.x, this.lastX - this.brushSize / 2);
    this.drawArea.y = Math.min(this.drawArea.y, this.lastY - this.brushSize / 2);
    this.drawArea.width = Math.max(this.drawArea.width, this.lastX + this.brushSize / 2);
    this.drawArea.height = Math.max(this.drawArea.height, this.lastY + this.brushSize / 2);

  }

  //画笔大小
  brushSize = 10;
  //画笔颜色
  brushColor = '#000000';
  //画笔类型
  brushType = 'pencil';
  // 开始绘制
  draw = false;
  lastX = 0;
  lastY = 0;

  //绘制的区域
  drawArea = {
    x: 1024,
    y: 1024,
    width: 0,
    height: 0
  }

  // 检查canvas的有效像素点的内容区域
  detectContentBoundingBox(canvas: HTMLCanvasElement, edgeTolerance: number = 1): BoundingBox | null {
    const ctx = canvas.getContext('2d', { willReadFrequently: true });
    if (!ctx) return null;

    const width = canvas.width;
    const height = canvas.height;
    const imageData = ctx.getImageData(0, 0, width, height);
    const data = new Uint32Array(imageData.data.buffer); // 使用32位视图提升性能
    // 边界检测参数
    let minX = width;
    let maxX = 0;
    let minY = height;
    let maxY = 0;

    // 垂直边界检测（上/下）
    const findVerticalEdge = (startY: number, endY: number, dir: 1 | -1): number => {
      for (let y = startY; dir === 1 ? y < endY : y > endY; y += dir) {
        for (let x = 0; x < width; x += 1) {
          const idx = y * width + Math.min(x, width - 1);
          if (data[idx] & 0xff000000) { // Alpha通道检测
            return y;
          }
        }
      }
      return dir === 1 ? height : -1;
    };

    // 水平边界检测（左/右）
    const findHorizontalEdge = (startX: number, endX: number, dir: 1 | -1): number => {
      for (let x = startX; dir === 1 ? x < endX : x > endX; x += dir) {
        for (let y = 0; y < height; y += 1) {
          const idx = Math.min(y, height - 1) * width + x;
          if (data[idx] & 0xff000000) {
            return x;
          }
        }
      }
      return dir === 1 ? width : -1;
    };

    // 执行边界检测
    minY = findVerticalEdge(0, height, 1);
    maxY = findVerticalEdge(height - 1, -1, -1);
    minX = findHorizontalEdge(0, width, 1);
    maxX = findHorizontalEdge(width - 1, -1, -1);

    // 处理全透明情况
    if (minX > maxX || minY > maxY) return null;

    // 应用边界容差
    return {
      x: Math.max(0, minX - edgeTolerance),
      y: Math.max(0, minY - edgeTolerance),
      width: Math.min(width - 1, maxX + edgeTolerance) - minX + 1,
      height: Math.min(height - 1, maxY + edgeTolerance) - minY + 1
    };
  }

  //更具this.drawArea 绘制的区域值 导出png格式的图片文件
  async exportContentAsImage() {
    // 创建临时 Canvas
    const tempCanvas = document.createElement('canvas');
    const tempCtx = tempCanvas.getContext('2d')!;

    // 检查 Canvas 的有效像素点的范围
    const ract = this.detectContentBoundingBox(this.lowerCanvas);

    if (ract && ract.width > 0 && ract.height > 0) {
      // 设置临时 Canvas 尺寸为目标区域大小
      tempCanvas.width = ract.width;
      tempCanvas.height = ract.height;

      // 将原 Canvas 的指定区域绘制到临时 Canvas
      tempCtx.drawImage(
        this.lowerCanvas,         // 源 Canvas
        ract.x, ract.y,          // 源区域起始坐标
        ract.width, ract.height,  // 源区域尺寸
        0, 0,           // 目标起始坐标
        ract.width, ract.height   // 目标尺寸（保持相同）
      );

      // 把tempCanvas的内容导出为png格式的图片文件File对象,然后销毁 tempCanvas
      const file = await new Promise<File>((resolve, reject) => {
        tempCanvas.toBlob((blob) => {
          const file = new File([blob!], 'graffiti.png', { type: 'image/png' });
          resolve(file);
        }, 'image/png');
      });
      tempCanvas.remove();
      return file;
    } else {
      return undefined;
    }
  }

}

const graffitiEditor = new GraffitiEditor();

export default graffitiEditor;